<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Use correct character set. -->
    <meta charset="utf-8" />
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Hello World!</title>
    <!-- <script src="../Build/Cesium/Cesium.js"></script> -->
    <script src="../Build/CesiumUnminified/Cesium.js"></script>
    <script src="jquery-2.0.3.js"></script>
    <script src="loadsh.js"></script>
    <style>
      @import url(../Build/Cesium/Widgets/widgets.css);

      html,
      body,
      #cesiumContainer {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>

  <body>
    <div id="cesiumContainer"></div>
    <script>
      var DemoTileProvider = function DemoTileProvider() {
        this._quadtree = undefined;
        this._tilingScheme = new Cesium.GeographicTilingScheme();
        this._errorEvent = new Cesium.Event();
        this._levelZeroMaximumError = Cesium.QuadtreeTileProvider.computeDefaultLevelZeroMaximumGeometricError(
          this._tilingScheme
        );
        this.cartographicLimitRectangle = Cesium.Rectangle.clone(
          Cesium.Rectangle.MAX_VALUE
        );
        this._renderState = undefined;
        this._blendRenderState = undefined;
        this._tilesToRenderByTextureCount = [];
        this._commandList = [];
        this._loadTiles1 = [];
      };
      Object.defineProperties(Cesium, DemoTileProvider.prototype, {
        quadtree: {
          get: function () {
            return this._quadtree;
          },
          set: function (value) {
            this._quadtree = value;
          },
        },
        ready: {
          get: function () {
            return true;
          },
        },
        tilingScheme: {
          get: function () {
            return this._tilingScheme;
          },
        },
        errorEvent: {
          get: function () {
            return this._errorEvent;
          },
        },
      });
      var rectangleIntersectionScratch = new Cesium.Rectangle();
      var cornerPositionsScratch = [
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
        new Cesium.Cartesian3(),
      ];
      DemoTileProvider.prototype.update = function (frameState) {
        this._quadtree.beginFrame(frameState);
        this._quadtree.render(frameState);
        this._quadtree.endFrame(frameState);
      };
      DemoTileProvider.prototype.clear = function (d) {
        if (d.length == 0) return;
        // debugger
        var dd = _.cloneDeep(d);
        _.forEach(dd, function (tile) {
          if (tile && tile.data && tile.data.geometryPrimitive) {
            scene.primitives.remove(tile.data.geometryPrimitive);
            dd.length = dd.length - 1;
          }
        });
        this._loadTiles1 = dd;
      };
      DemoTileProvider.prototype.initialize = function (frameState) {};
      DemoTileProvider.prototype.beginUpdate = function (frameState) {};
      DemoTileProvider.prototype.endUpdate = function (frameState) {
        //this.clear(_.difference(this._loadTiles1, prim._tilesToRender))
      };

      DemoTileProvider.prototype.getLevelMaximumGeometricError = function (
        level
      ) {
        return this._levelZeroMaximumError / (1 << level);
      };
      var k = 0;
      DemoTileProvider.prototype.loadTile = function (frameState, tile) {
        var styleOption = JSON.parse(
          '{"level_max":20,"classificationType":2,"fill":"rgba(122, 188, 124, 0.5)","layertype":"polygonbase","outline":false,"material":{"red":0.47843137254901963,"green":0.7372549019607844,"blue":0.48627450980392156,"alpha":0.5},"outlineWidth":1,"far":9999999999999,"effect":0,"outlineColor":"rgba(68,66,66,0.5)","level_min":11,"ground":0,"near":0}'
        );
        var options = {};
        if (tile.state === Cesium.QuadtreeTileLoadState.START) {
          tile.data = {
            lines: [],
            geometryPrimitive: undefined,
          };
          if (tile.level < 16) {
            var tileUrl = "http://192.168.1.40:8090/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=swagger%3A_20200409064613_nanjing&STYLE=&TILEMATRIX=EPSG%3A4326%3A%7Bz%7D&TILEMATRIXSET=EPSG%3A4326&FORMAT=application%2Fjson%3Btype%3Dgeojson&TILECOL=%7Bx%7D&TILEROW=%7By%7D"
              .replace(window.encodeURIComponent("{x}"), tile.x)
              .replace(window.encodeURIComponent("{y}"), tile.y)
              .replace(window.encodeURIComponent("{z}"), tile.level);

            $.ajax({
              url: tileUrl,
              type: "get",
              dataType: "json",
              success: function (data) {
                var geometries = [];
                function fun(arr) {
                  for (var i = 0; i < arr.length; i++) {
                    if (Array.isArray(arr[i])) {
                      fun(arr[i]);
                    } else {
                      newArr.push(arr[i]);
                    }
                  }
                }
                function createobj() {
                  //options.extrudedHeight = parseFloat(that._option.extrudedHeight);
                  options.material = Cesium.Color.RED;
                  if (newArr.length >= 2) {
                    var pos = Cesium.Cartesian3.fromDegreesArray(newArr);
                    options.polygonHierarchy = new Cesium.PolygonHierarchy(pos);
                    //基础面
                    var extrudedPolygon = new Cesium.PolygonGeometry(options);
                    //var geometry = that._cesium.PolygonGeometry.createGeometry(extrudedPolygon);
                    var geometryInstance = new Cesium.GeometryInstance({
                      id: feature,
                      geometry: extrudedPolygon,
                      attributes: {
                        color: new Cesium.ColorGeometryInstanceAttribute.fromColor(
                          options.material
                        ),
                      },
                    });
                    geometries.push(geometryInstance);
                  }
                  //geometries.push(geometryInstance1);
                }
                for (var i = 0; i < data.features.length; i++) {
                  var newArr = [];
                  var feature = data.features[i];

                  //fun(data.features[i].geometry.coordinates[0]);
                  //解析坐标
                  if (
                    Array.isArray(feature.geometry.coordinates) &&
                    feature.geometry.coordinates.length > 0
                  ) {
                    if (Array.isArray(feature.geometry.coordinates[0][0])) {
                      for (
                        var j = 0;
                        j < feature.geometry.coordinates.length;
                        j++
                      ) {
                        newArr = [];
                        feature.geometry.coordinates[j].pop();
                        fun(feature.geometry.coordinates[j]);
                        createobj(newArr);
                      }
                    } else {
                      fun(feature.geometry.coordinates);
                      createobj(newArr);
                    }
                  }
                }

                var Primitive = new Cesium.GroundPrimitive({
                  geometryInstances: geometries,
                  appearance: new Cesium.PerInstanceColorAppearance({
                    translucent: false,
                  }),
                  classificationType: Cesium.ClassificationType.BOTH,
                });
                viewer.scene.primitives.add(Primitive);
                tile.customData.push(Primitive);
                tile.state = Cesium.QuadtreeTileLoadState.LOADING;
                if (tile.state === Cesium.QuadtreeTileLoadState.LOADING) {
                  tile.state = Cesium.QuadtreeTileLoadState.DONE;
                  tile.renderable = true;
                  //}
                }
              },
              error: function () {},
            });
          } else {
            tile.state = Cesium.QuadtreeTileLoadState.DONE;
            tile.renderable = true;
            return;
          }

          tile.state = Cesium.QuadtreeTileLoadState.LOADING;
        }
      };
      DemoTileProvider.prototype.computeTileVisibility = function (
        tile,
        frameState,
        occluders
      ) {
        var distance = this.computeDistanceToTile(tile, frameState);
        tile._distance = distance;
        if (frameState.fog.enabled) {
          if (Cesium.Math.fog(distance, frameState.fog.density) >= 1.0) {
            return Cesium.Visibility.NONE;
          }
        }

        var surfaceTile = tile.data;
        var tileBoundingRegion = surfaceTile.tileBoundingRegion;

        if (surfaceTile.boundingVolumeSourceTile === undefined) {
          // We have no idea where this tile is, so let's just call it partially visible.
          return Cesium.Visibility.PARTIAL;
        }

        var cullingVolume = frameState.cullingVolume;
        var boundingVolume = surfaceTile.orientedBoundingBox;

        if (!boundingVolume && surfaceTile.renderedMesh) {
          boundingVolume = surfaceTile.renderedMesh.boundingSphere3D;
        }

        // Check if the tile is outside the limit area in cartographic space
        surfaceTile.clippedByBoundaries = false;
        var clippedCartographicLimitRectangle = clipRectangleAntimeridian(
          tile.rectangle,
          this.cartographicLimitRectangle
        );
        var areaLimitIntersection = Cesium.Rectangle.simpleIntersection(
          clippedCartographicLimitRectangle,
          tile.rectangle,
          rectangleIntersectionScratch
        );
        if (!areaLimitIntersection) {
          return Cesium.Visibility.NONE;
        }
        if (!Cesium.Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
          surfaceTile.clippedByBoundaries = true;
        }

        if (frameState.mode !== Cesium.SceneMode.SCENE3D) {
          boundingVolume = boundingSphereScratch;
          BoundingSphere.fromRectangleWithHeights2D(
            tile.rectangle,
            frameState.mapProjection,
            tileBoundingRegion.minimumHeight,
            tileBoundingRegion.maximumHeight,
            boundingVolume
          );
          Cartesian3.fromElements(
            boundingVolume.center.z,
            boundingVolume.center.x,
            boundingVolume.center.y,
            boundingVolume.center
          );

          if (
            frameState.mode === SceneMode.MORPHING &&
            surfaceTile.renderedMesh
          ) {
            boundingVolume = BoundingSphere.union(
              surfaceTile.renderedMesh.boundingSphere3D,
              boundingVolume,
              boundingVolume
            );
          }
        }

        if (!boundingVolume) {
          return Cesium.Intersect.INTERSECTING;
        }

        var clippingPlanes = this._clippingPlanes;
        if (clippingPlanes && clippingPlanes.enabled) {
          var planeIntersection = clippingPlanes.computeIntersectionWithBoundingVolume(
            boundingVolume
          );
          tile.isClipped = planeIntersection !== Intersect.INSIDE;
          if (planeIntersection === Cesium.Intersect.OUTSIDE) {
            return Cesium.Visibility.NONE;
          }
        }

        var intersection = cullingVolume.computeVisibility(boundingVolume);
        if (intersection === Cesium.Intersect.OUTSIDE) {
          if (tile.data.geometryPrimitive) {
            scene.primitives.remove(tile.data.geometryPrimitive);
            tile.data = undefined;
          }
          return Cesium.Visibility.NONE;
        }

        var ortho3D =
          frameState.mode === Cesium.SceneMode.SCENE3D &&
          frameState.camera.frustum instanceof Cesium.OrthographicFrustum;
        if (
          frameState.mode === Cesium.SceneMode.SCENE3D &&
          !ortho3D &&
          occluders
        ) {
          var occludeePointInScaledSpace =
            surfaceTile.occludeePointInScaledSpace;
          if (!occludeePointInScaledSpace) {
            return intersection;
          }

          if (
            occluders.ellipsoid.isScaledSpacePointVisible(
              occludeePointInScaledSpace
            )
          ) {
            return intersection;
          }

          return Cesium.Visibility.NONE;
        }

        return intersection;
      };
      DemoTileProvider.prototype.canRefine = function (
        tile,
        frameState,
        occluders
      ) {
        if (tile.level < 16) return true;
        return false;
      };
      DemoTileProvider.prototype.showTileThisFrame = function (
        tile,
        context,
        frameState,
        commandList
      ) {
        if (tile.data.geometryPrimitive) {
          // context.passes.pick = true
          //tile.data.geometryPrimitive.update(context, frameState, commandList);
        }
      };
      DemoTileProvider.prototype.computeDistanceToTile = function (
        tile,
        frameState
      ) {
        // The distance should be:
        // 1. the actual distance to the tight-fitting bounding volume, or
        // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
        //
        // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
        // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
        // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
        // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
        // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
        // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
        // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
        // based that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
        // better (faster) than loading tiles that are too detailed.
        var heightSource = updateTileBoundingRegion(
          tile,
          this.terrainProvider,
          frameState
        );
        var surfaceTile = tile.data;
        var tileBoundingRegion = surfaceTile.tileBoundingRegion;

        if (heightSource === undefined) {
          // Can't find any min/max heights anywhere? Ok, let's just say the
          // tile is really far away so we'll load and render it rather than
          // refining.
          return 9999999999.0;
        } else if (surfaceTile.boundingVolumeSourceTile !== heightSource) {
          // Heights are from a new source tile, so update the bounding volume.
          surfaceTile.boundingVolumeSourceTile = heightSource;

          var rectangle = tile.rectangle;
          if (
            rectangle &&
            rectangle.width < Cesium.Math.PI_OVER_TWO + Cesium.Math.EPSILON5
          ) {
            surfaceTile.orientedBoundingBox = Cesium.OrientedBoundingBox.fromRectangle(
              tile.rectangle,
              tileBoundingRegion.minimumHeight,
              tileBoundingRegion.maximumHeight,
              tile.tilingScheme.ellipsoid,
              surfaceTile.orientedBoundingBox
            );

            surfaceTile.occludeePointInScaledSpace = computeOccludeePoint(
              this,
              surfaceTile.orientedBoundingBox.center,
              tile.rectangle,
              tileBoundingRegion.maximumHeight,
              surfaceTile.occludeePointInScaledSpace
            );
          }
        }

        var min = tileBoundingRegion.minimumHeight;
        var max = tileBoundingRegion.maximumHeight;

        if (surfaceTile.boundingVolumeSourceTile !== tile) {
          var cameraHeight = frameState.camera.positionCartographic.height;
          var distanceToMin = Math.abs(cameraHeight - min);
          var distanceToMax = Math.abs(cameraHeight - max);
          if (distanceToMin > distanceToMax) {
            tileBoundingRegion.minimumHeight = min;
            tileBoundingRegion.maximumHeight = min;
          } else {
            tileBoundingRegion.minimumHeight = max;
            tileBoundingRegion.maximumHeight = max;
          }
        }

        var result = tileBoundingRegion.distanceToCamera(frameState);

        tileBoundingRegion.minimumHeight = min;
        tileBoundingRegion.maximumHeight = max;

        return result;
      };

      function updateTileBoundingRegion(tile, terrainProvider, frameState) {
        var surfaceTile = tile.data;
        if (surfaceTile === undefined) {
          surfaceTile = tile.data = new Cesium.GlobeSurfaceTile();
        }

        if (surfaceTile.tileBoundingRegion === undefined) {
          surfaceTile.tileBoundingRegion = new Cesium.TileBoundingRegion({
            computeBoundingVolumes: false,
            rectangle: tile.rectangle,
            ellipsoid: tile.tilingScheme.ellipsoid,
            minimumHeight: 0.0,
            maximumHeight: 0.0,
          });
        }
        return tile;
      }

      function clipRectangleAntimeridian(
        tileRectangle,
        cartographicLimitRectangle
      ) {
        if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
          return cartographicLimitRectangle;
        }
        var splitRectangle = Rectangle.clone(
          cartographicLimitRectangle,
          splitCartographicLimitRectangleScratch
        );
        var tileCenter = Rectangle.center(
          tileRectangle,
          rectangleCenterScratch
        );
        if (tileCenter.longitude > 0.0) {
          splitRectangle.east = CesiumMath.PI;
        } else {
          splitRectangle.west = -CesiumMath.PI;
        }
        return splitRectangle;
      }

      function computeOccludeePoint(
        tileProvider,
        center,
        rectangle,
        height,
        result
      ) {
        var ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
        var ellipsoid = ellipsoidalOccluder.ellipsoid;

        var cornerPositions = cornerPositionsScratch;
        Cesium.Cartesian3.fromRadians(
          rectangle.west,
          rectangle.south,
          height,
          ellipsoid,
          cornerPositions[0]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.east,
          rectangle.south,
          height,
          ellipsoid,
          cornerPositions[1]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.west,
          rectangle.north,
          height,
          ellipsoid,
          cornerPositions[2]
        );
        Cesium.Cartesian3.fromRadians(
          rectangle.east,
          rectangle.north,
          height,
          ellipsoid,
          cornerPositions[3]
        );

        return ellipsoidalOccluder.computeHorizonCullingPoint(
          center,
          cornerPositions,
          result
        );
      }
      DemoTileProvider.prototype.isDestroyed = function () {
        return false;
      };
      DemoTileProvider.prototype.updateForPick = function (frameState) {
        // var drawCommands = this._drawCommands;
        // for (var i = 0, length = this._usedDrawCommands; i < length; ++i) {
        // frameState.commandList.push(drawCommands[i]);
        // }
        frameState.commandList = this._commandList;
      };
      DemoTileProvider.prototype.destroy = function () {
        return Cesium.destroyObject(this);
      };
      // var viewer = new Cesium.Viewer('cesiumContainer');
      var viewer = new Cesium.Viewer("cesiumContainer", {
        //需要进行可视化的数据源的集合
        animation: false, //是否显示动画控件
        shouldAnimate: true,
        homeButton: false, //是否显示Home按钮
        fullscreenButton: false, //是否显示全屏按钮
        baseLayerPicker: false, //是否显示图层选择控件
        geocoder: false, //是否显示地名查找控件
        timeline: false, //是否显示时间线控件
        sceneModePicker: true, //是否显示投影方式控件
        navigationHelpButton: false, //是否显示帮助信息控件
        infoBox: false, //是否显示点击要素之后显示的信息
        requestRenderMode: true, //启用请求渲染模式
        scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存
        sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
        fullscreenElement: document.body, //全屏时渲染的HTML元素 暂时没发现用处
        selectionIndicator: true,
        infoBox: true,
        //天地图是官方开元的地图，不需要密钥
        imageryProvider: new Cesium.UrlTemplateImageryProvider({
          url:
            "http://mt1.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}&s=Gali",
        }),
      });

      var scene = viewer.scene;
      var primitives = scene.primitives;

      var prim = new Cesium.QuadtreePrimitive({
        tileProvider: new DemoTileProvider(),
      });

      primitives.add(prim);

      var rectangleInstance = new Cesium.GeometryInstance({
        geometry: new Cesium.RectangleGeometry({
          rectangle: Cesium.Rectangle.fromDegrees(-140.0, 30.0, -100.0, 40.0),
          vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
        }),
        attributes: {
          color: new Cesium.ColorGeometryInstanceAttribute(0.0, 1.0, 1.0, 0.5),
        },
      });
      var ellipsoidInstance = new Cesium.GeometryInstance({
        geometry: new Cesium.EllipsoidGeometry({
          radii: new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
          vertexFormat: Cesium.VertexFormat.POSITION_AND_NORMAL,
        }),
        modelMatrix: Cesium.Matrix4.multiplyByTranslation(
          Cesium.Transforms.eastNorthUpToFixedFrame(
            Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)
          ),
          new Cesium.Cartesian3(0.0, 0.0, 500000.0),
          new Cesium.Matrix4()
        ),
        attributes: {
          color: Cesium.ColorGeometryInstanceAttribute.fromColor(
            Cesium.Color.AQUA
          ),
        },
      });
      scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: [rectangleInstance, ellipsoidInstance],
          appearance: new Cesium.PerInstanceColorAppearance(),
        })
      );

      var k = 0;
      Cesium.Scene.prototype.screenToWorld = L;
      function L(t, n) {
        if (viewer.canvas.width <= 0 || viewer.canvas.height <= 0) return;
        if (k > 0) return;
        var r = {
          level: 16,
          callback: function (s) {
            console.log(s);
          },
          pickPrimitive: undefined,
          pick: undefined,
          includeUndergroundSurface: !0,
        };
        var i = $.extend(!0, {}, r, n);
        var s;
        var o;
        try {
          k++;
          o = viewer.scene.pick(t);
        } catch (u) {
          console.log("Pick error!");
        } finally {
          k--;
        }
        var a =
          i.includeUndergroundSurface &&
          Cesium.defined(o) &&
          Cesium.defined(o.id) &&
          o.id == "undergroundSurface";
        if (
          Cesium.defined(o) &&
          Cesium.defined(o.primitive) &&
          viewer.scene.pickPositionSupported
        )
          viewer.scene.pickTranslucentDepth &&
            o.primitive._appearance &&
            o.primitive._appearance.translucent &&
            C(),
            (s = viewer.scene.pickPosition(t)),
            i.callback != undefined && i.callback(s);
        // else if (viewer.scene.pickPositionSupported)
        //     s = viewer.scene.pickPosition(t),
        //         i.callback != undefined && i.callback(s);
        else {
          var f = viewer.camera.getPickRay(t);
          s = viewer.scene.globe.pick(f, viewer.scene);
          if (i.callback != undefined) {
            var l = viewer.scene.globe.ellipsoid.cartesianToCartographic(s),
              c = Cesium.sampleTerrain(viewer.terrainProvider, i.level, [l]);
            Cesium.when(c, function (e) {
              e[0].height != undefined &&
                (s = viewer.scene.globe.ellipsoid.cartographicToCartesian(
                  e[0]
                )),
                i.callback(s);
            });
          }
        }
        return (
          n != undefined &&
            o != undefined &&
            ((n.pickPrimitive = o.primitive), (n.id = o.id), (n.pick = o)),
          s
        );
      }
      var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
      handler.setInputAction(function (e) {
        var n = {};
        viewer.scene.screenToWorld(e.position, n);
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    </script>
  </body>
</html>
